/*
 * Name        : BaseTask.java
 * Classes     : BaseTask
 * Version     : 1.0
 * Date        : 2013-08-29
 *
 * Copyright 2013 CMCC.  All rights reserved.
 * This material, including documentation and any related computer
 * programs, is protected by copyright controlled by CMCC.  All
 * rights are reserved.  Copying, including reproducing, storing,
 * adapting or translating, any or all of this material requires the
 * prior written consent of CMCC.  This material also contains
 * confidential information which may not be disclosed to others
 * without the prior written consent of CMCC.
 */

package com.xgkj.diyiketang.http.engine;

import com.xgkj.diyiketang.http.BaseRequest;
import com.xgkj.diyiketang.http.BaseResponse;

import java.util.LinkedList;
import java.util.List;




/**
 * Class Name  : BaseTask
 * Author      : Tu Yuanlin
 * Date        : 13-9-3
 * Description : Task base class, sub class should create and add request into mRequestQueue
 */
public abstract class BaseTask implements RequestEventListener, Runnable {
    protected List<BaseRequest> mRequestQueue;
    protected List<TaskEventHandler> mTaskHandlerList;
    protected int mType;
    protected int mId;
    protected int mPhase;
    protected boolean mIsCancelled;
    protected boolean mIsCompleted;
    private BaseRequest currentRequest;

    protected static final int TASK_PHASE_INIT = 0;
    protected static final int TASK_PHASE_RUNNING = 1;

    private static int taskMaxId = 1;

    /**
     * Constructor of BaseTask, init members and assign task id.
     *
     * @param type task type
     */
    protected BaseTask(int type) {
        mType = type;
        mId = BaseTask.taskMaxId;
        mPhase = TASK_PHASE_INIT;
        BaseTask.taskMaxId++;
        mRequestQueue = new LinkedList<BaseRequest>();
        mTaskHandlerList = new LinkedList<TaskEventHandler>();
    }

    /**
     * Called when check if there is new request in request queue, and it should be override by sub-classes if
     * want to initialize some requests.
     */
    protected void prepareRequest() {

    }

    /**
     * Called before a request is started, and it should be override by sub-classes if want to do something before
     * request is started
     */
    protected void preStartRequest() {

    }

    /**
     * Called after a request is started, and it should be override by sub-classes if want to do something after
     * request is started
     */
    protected void postStartRequest() {

    }

    /**
     * Cancel task, if the task is cancelled, it won't notify listeners any message.
     */
    public void cancel() {
        mIsCancelled = true;
        mTaskHandlerList.clear();
    }

    /**
     * Get task type
     *
     * @return Task type
     */
    public int getType() {
        return mType;
    }

    /**
     * Get task id
     *
     * @return Task id
     */
    public int getId() {
        return mId;
    }

    /**
     * Add request into request queue
     *
     * @param request the reuqest need be added
     */
    public void addRequest(BaseRequest request) {
        request.addListener(this);
        mRequestQueue.add(request);
    }

    /**
     * Add listener to handle task event, including fail, success and message.
     *
     * @param listener the listener to handle task event
     */
    public void addListener(TaskEventListener listener) {
        if (listener == null) {
            return;
        }

        if (findListener(listener) == null) {
            TaskEventHandler handler = new TaskEventHandler(listener);
            synchronized (mTaskHandlerList) {
                mTaskHandlerList.add(handler);
            }
        }
    }

    /**
     * Remove listener which has added into listener list.
     *
     * @param listener the listener need be removed from list
     */
    public void removeListener(TaskEventListener listener) {
        if (listener == null) {
            return;
        }

        TaskEventHandler handler = findListener(listener);
        if (handler != null) {
            synchronized (mTaskHandlerList) {
                mTaskHandlerList.remove(handler);
            }
        }
    }

    /**
     * Notify all listeners that task is failed, and send error information to listener.
     *
     * @param errorCode the code indicate error type
     * @param errorMsg the string message describe error information
     */
    protected void notifyTaskError(int errorCode, String errorMsg) {
        if (mIsCancelled) {
            return;
        }

        synchronized (mTaskHandlerList) {
            for (TaskEventHandler handler : mTaskHandlerList) {
        	    handler.handleTaskError(mId, errorCode, errorMsg);
            }
            mTaskHandlerList.clear();
            mIsCompleted = true;
        }
    }

    /**
     * Notify all listeners the new task message, message content is stored in data
     *
     * @param data the message content
     */
    protected void notifyTaskMessage(Object data) {
        if (mIsCancelled) {
            return;
        }

        synchronized (mTaskHandlerList) {
            for (TaskEventHandler handler : mTaskHandlerList) {
                handler.handleTaskMessage(mId, data);
            }
            mTaskHandlerList.clear();
            mIsCompleted = true;
        }
    }

    /**
     * Notify all listeners that task is completed, and send result and data to listener.
     *
     * @param result task result code
     * @param data the response data when task is completed
     */
    protected void notifyTaskCompleted(int result, Object data) {
        if (mIsCancelled) {
            return;
        }
        

        synchronized (mTaskHandlerList) {
            for (TaskEventHandler handler : mTaskHandlerList) {
                handler.handleTaskCompleted(mId, result, data);
            }
            mTaskHandlerList.clear();
            mIsCompleted = true;
        }
    }

    @Override
    public void handleResponse(BaseRequest request, BaseResponse response) {
        if (request == currentRequest) {
            currentRequest = null;
        }
    }

    @Override
    public void run() {
        while (!mIsCancelled && !mIsCompleted) {
            try {
                prepareRequest();

                if (mRequestQueue.size() > 0) {
                    if (mPhase == TASK_PHASE_INIT) {
                        mPhase = TASK_PHASE_RUNNING;
                    }
                    preStartRequest();

                    currentRequest = mRequestQueue.get(0);
                    mRequestQueue.remove(0);
                    currentRequest.startRequest();

                    postStartRequest();
                } else {
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                notifyTaskError(TaskResultCode.UNKNOWN_EXCEPTION, null);
            } catch (Exception e) {
                e.printStackTrace();
                notifyTaskError(TaskResultCode.UNKNOWN_EXCEPTION, null);
            }
        }
    }

    protected void setPhase(int phase) {
        mPhase = phase;
    }

    private TaskEventHandler findListener(TaskEventListener listener) {
        if (listener == null || mTaskHandlerList == null) {
            return null;
        }

        for (TaskEventHandler handler : mTaskHandlerList) {
            if (handler.contains(listener)) {
                return handler;
            }
        }

        return null;
    }

   
}
